home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / debug.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  7KB  |  317 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.  See the file COPYING for details.
  4.  
  5.    $Id: debug.c,v 1.20 2001/02/15 08:39:45 drscholl Exp $ */
  6.  
  7. /* This is a very simple memory management debugger.  It's useful for detecting
  8.    memory leaks, references to uninitialzed memory, bad pointers, buffer
  9.    overflow and getting an idea of how much memory is used by a program. */
  10.  
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <ctype.h>
  15. #include "debug.h"
  16.  
  17. #ifdef DEBUG
  18.  
  19. #define MIN(a,b) ((a<b)?a:b)
  20.  
  21. /* tunable parameter.  if you have a large amount of memory allocated, setting
  22.    this value higher will result in faster validation of pointers */
  23. #define SIZE 4099
  24.  
  25. typedef struct _block
  26. {
  27.     void   *val;
  28.     int     len;
  29.     const char *file;
  30.     int     line;
  31.     struct _block *next;
  32. }
  33. BLOCK;
  34.  
  35. static BLOCK *Allocation[SIZE];
  36. static int Memory_Usage = 0;
  37.  
  38. void
  39. debug_init (void)
  40. {
  41.     memset (Allocation, 0, sizeof (Allocation));
  42. }
  43.  
  44. #if SIZEOF_LONG == 8
  45. #define SHIFT 3
  46. #else
  47. #define SHIFT 2
  48. #endif
  49.  
  50. /* hash the pointer value for insertion into the table */
  51. static int
  52. debug_hash (void *ptr)
  53. {
  54.     int     hash;
  55.  
  56.     /* pointers are allocated on either 4 or 8 bytes boundaries, so we want
  57.        to ignore those values.  this will cause consecutive pointers to hash
  58.        to the next bin */
  59.     hash = ((unsigned long) ptr) >> SHIFT;
  60.     return ((hash & 0x7fffffff) % SIZE);
  61. }
  62.  
  63. static int
  64. debug_overflow (BLOCK * block, const char *func)
  65. {
  66.     if (*((unsigned char *) block->val + block->len) != END_BYTE)
  67.     {
  68.     fprintf (stderr,
  69.          "debug_%s: buffer overflow detected in data allocated at %s:%d\n",
  70.          func, block->file, block->line);
  71.     return 1;
  72.     }
  73.     return 0;
  74. }
  75.  
  76. static void
  77. debug_exhausted (const char *file, int line)
  78. {
  79.     fprintf (stderr,
  80.          "debug_malloc(): memory exhausted at %s:%d (%d bytes allocated)\n",
  81.          file, line, Memory_Usage);
  82. }
  83.  
  84. void   *
  85. debug_malloc (int bytes, const char *file, int line)
  86. {
  87.     BLOCK  *block, **ptr;
  88.     int     offset;
  89.  
  90.     if (bytes == 0)
  91.     {
  92.     fprintf (stderr, "debug_malloc(): 0 bytes requested at %s:%d\n",
  93.          file, line);
  94.     return 0;
  95.     }
  96.  
  97.     block = malloc (sizeof (BLOCK));
  98.     if (!block)
  99.     {
  100.     debug_exhausted (file, line);
  101.     return 0;
  102.     }
  103.     block->val = malloc (bytes + 1);
  104.     if (!block->val)
  105.     {
  106.     debug_exhausted (__FILE__, __LINE__);
  107.     free (block);
  108.     return 0;
  109.     }
  110.     Memory_Usage += bytes;
  111.     block->len = bytes;
  112.     block->file = file;
  113.     block->line = line;
  114.     memset (block->val, ALLOC_BYTE, bytes);
  115.     *((unsigned char *) block->val + bytes) = END_BYTE;
  116.  
  117.     offset = debug_hash (block->val);
  118.     for (ptr = &Allocation[offset]; *ptr; ptr = &(*ptr)->next)
  119.     {
  120.     if (block->val < (*ptr)->val)
  121.         break;
  122.     }
  123.     block->next = *ptr;
  124.     *ptr = block;
  125.     return block->val;
  126. }
  127.  
  128. void   *
  129. debug_calloc (int count, int bytes, const char *file, int line)
  130. {
  131.     void   *ptr = debug_malloc (count * bytes, file, line);
  132.  
  133.     if (!ptr)
  134.     return 0;
  135.     memset (ptr, 0, count * bytes);
  136.     return ptr;
  137. }
  138.  
  139. static BLOCK *
  140. find_block (void *ptr)
  141. {
  142.     int     offset = debug_hash (ptr);
  143.     BLOCK  *block;
  144.  
  145.     for (block = Allocation[offset]; block && ptr > block->val;
  146.      block = block->next);
  147.     return ((block != 0 && ptr == block->val) ? block : 0);
  148. }
  149.  
  150. void   *
  151. debug_realloc (void *ptr, int bytes, const char *file, int line)
  152. {
  153.     void   *newptr;
  154.     BLOCK  *block = 0;
  155.  
  156.     if (bytes == 0)
  157.     {
  158.     debug_free (ptr, file, line);
  159.     return 0;
  160.     }
  161.     if (ptr)
  162.     {
  163.     block = find_block (ptr);
  164.     if (!block)
  165.     {
  166.         fprintf (stderr,
  167.              "debug_realloc(): invalid pointer at %s:%d\n", file,
  168.              line);
  169.         return 0;
  170.     }
  171.     debug_overflow (block, "realloc");
  172.     }
  173.     newptr = debug_malloc (bytes, file, line);
  174.     if (!newptr)
  175.     return 0;
  176.     if (ptr)
  177.     {
  178.     memcpy (newptr, ptr, MIN (bytes, block->len));
  179.     debug_free (ptr, file, line);
  180.     }
  181.     return newptr;
  182. }
  183.  
  184. void
  185. debug_free (void *ptr, const char *file, int line)
  186. {
  187.     BLOCK **list, *block = 0;
  188.     int     offset;
  189.  
  190.     if (!ptr)
  191.     {
  192.     fprintf (stderr,
  193.          "debug_free: attempt to free NULL pointer at %s:%d\n",
  194.          file, line);
  195.     return;
  196.     }
  197.     offset = debug_hash (ptr);
  198.     if (!Allocation[offset])
  199.     {
  200.     fprintf (stderr,
  201.          "debug_free: attempt to free bogus pointer at %s:%d\n",
  202.          file, line);
  203.     return;
  204.     }
  205.     for (list = &Allocation[offset]; *list; list = &(*list)->next)
  206.     {
  207.     if ((*list)->val == ptr)
  208.         break;
  209.     }
  210.     if (!*list)
  211.     {
  212.     fprintf (stderr,
  213.          "debug_free: attempt to free bogus pointer at %s:%d\n",
  214.          file, line);
  215.     return;
  216.     }
  217.     block = *list;
  218.     /* remove the block from the list */
  219.     *list = (*list)->next;
  220.  
  221.     debug_overflow (block, "free");
  222.     memset (block->val, FREE_BYTE, block->len);
  223.     free (block->val);
  224.     Memory_Usage -= block->len;
  225.     free (block);
  226. }
  227.  
  228. #if 0
  229. /* display the contents of an allocated block */
  230. static void
  231. debug_dump (BLOCK * block)
  232. {
  233.     int     i;
  234.  
  235.     fputc ('\t', stderr);
  236.     for (i = 0; i < block->len && i < 8; i++)
  237.     fprintf (stderr, "%02x ", *((unsigned char *) block->val + i));
  238.     fputc ('\t', stderr);
  239.     for (i = 0; i < block->len && i < 8; i++)
  240.     fprintf (stderr, "%c",
  241.          isprint (*((unsigned char *) block->val + i)) ?
  242.          *((unsigned char *) block->val + i) : '.');
  243.     fputc ('\n', stderr);
  244. }
  245. #endif
  246.  
  247. void
  248. debug_cleanup (void)
  249. {
  250.     int     i;
  251.     BLOCK  *block;
  252.  
  253.     for (i = 0; i < SIZE; i++)
  254.     {
  255.     for (block = Allocation[i]; block; block = block->next)
  256.     {
  257.         debug_overflow (block, "cleanup");
  258.         fprintf (stderr, "debug_cleanup: %d bytes allocated at %s:%d\n",
  259.              block->len, block->file, block->line);
  260. #if 0
  261.         debug_dump (block);
  262. #endif
  263.     }
  264.     }
  265.     if (Memory_Usage)
  266.     fprintf (stderr, "debug_cleanup: %d bytes total\n", Memory_Usage);
  267. }
  268.  
  269. char   *
  270. debug_strdup (const char *s, const char *file, int line)
  271. {
  272.     char   *r;
  273.  
  274.     r = debug_malloc (strlen (s) + 1, file, line);
  275.     if (!r)
  276.     return 0;
  277.     strcpy (r, s);
  278.     return r;
  279. }
  280.  
  281. /* check to see if a pointer is valid.  ptr can be an offset into an
  282.  allocation block, so don't use find_block() */
  283. int
  284. debug_valid (void *ptr, int len)
  285. {
  286.     BLOCK  *block;
  287.     int     offset;
  288.  
  289.     offset = debug_hash (ptr);
  290.     for (block = Allocation[offset];
  291.      block && (char *) ptr > (char *) block->val + block->len;
  292.      block = block->next)
  293.     ;
  294.     if (!block)
  295.     {
  296.     fprintf (stderr, "debug_valid: invalid pointer\n");
  297.     return 0;        /* not found */
  298.     }
  299.     /* ensure the pointer is within this block */
  300.     if (ptr < block->val)
  301.     {
  302.     fprintf (stderr, "debug_valid: invalid pointer\n");
  303.     return 0;
  304.     }
  305.     if (debug_overflow (block, "valid"))
  306.     return 0;
  307.     /* ensure that there are at least `len' bytes available */
  308.     return (((char *) ptr + len <= (char *) block->val + block->len));
  309. }
  310.  
  311. int
  312. debug_usage (void)
  313. {
  314.     return Memory_Usage;
  315. }
  316. #endif /* DEBUG */
  317.